#pragma once
#include "Socket.hpp"
#include "Log.hpp"
#include <sys/epoll.h>
using namespace LogModule;
using namespace SocketModule;

class EpollServer
{
    const static int size = 64;
    const static int defaultfd = -1;

public:
    EpollServer(int port) : _listensock(std::make_unique<TcpSocket>()), _isrunning(false),_epfd(defaultfd)
    {
        _listensock->BuildTcpSocketMethod(port);//用端口定义_listensock
        _epfd=epoll_create(256);//创建epoll套接字
        if(_epfd<0)
        {
            LOG(LogLevel::FATAL)<<"EPOLL CREATE ERROR";
            exit(errno);
        }
        LOG(LogLevel::INFO)<<"EPOLL CREATE SUCCESS";
        struct epoll_event ev;
        ev.events=EPOLLIN;
        ev.data.fd=_listensock->Fd();
        int n=epoll_ctl(_epfd,EPOLL_CTL_ADD,_listensock->Fd(),&ev);//将_listensock套接字添加到epoll监听当中
        if(n<0)
        {
            LOG(LogLevel::ERROR)<<"ADD LISTENING ERROR";
            exit(errno);
        }
    }
    void Start()
    {
        int timeout = -1;
        _isrunning = true;
        while (_isrunning)
        {
            int n = epoll_wait(_epfd, _revs,size, timeout);
            switch (n)
            {
            case -1:
                LOG(LogLevel::ERROR) << "EPOLL ERROR";
                break;
            case 0:
                LOG(LogLevel::INFO) << "EPOLL TIME OUT....";
                break;
            default:
                LOG(LogLevel::INFO) << "THERE HAS A FACTOR ALREADY";
                Dispatcher(n);
                break;
            }
        }
        _isrunning = false;
    }
    void Dispatcher(int n)
    {
        LOG(LogLevel::DEBUG)<<"EVERY READY...";
        for (int i = 0; i < n; i++)
        {
            int sockfd=_revs[i].data.fd;
            uint32_t revent=_revs[i].events;
            if(revent&EPOLLIN)
            {
                if(sockfd==_listensock->Fd())
                {
                    Accepter();
                }
                else
                {
                    Recver(sockfd);
                }
            }
        }
    }
    void Accepter()
    {
        InetAddr client;
        int sockfd=_listensock->Accept(&client);
        LOG(LogLevel::INFO)<<"SOCKFD[]:"<<sockfd;
        if(sockfd>0)
        {
            LOG(LogLevel::INFO)<<"GET A NEW LINK,SOCKFD:"<<sockfd<<",CLIENT IS: "<<client.StringAddr();
            struct epoll_event ev;
            ev.events=EPOLLIN;
            ev.data.fd=sockfd;
            int n=epoll_ctl(_epfd,EPOLL_CTL_ADD,sockfd,&ev);
            if(n<0)
            {
                LOG(LogLevel::WARNING)<<"ADD LISTENSOCKFD FAILED";
            }
            else
            {
                LOG(LogLevel::INFO)<<"EPOLL_CTL ADD SOCKFD SUCCESS"<<sockfd;
            }
        }

    }
    void Recver(int sockfd)
    {
        char buffer[1024];
        int ret=recv(sockfd,buffer,sizeof(buffer),0);
        if(ret>0)
        {
            buffer[ret]=0;
            LOG(LogLevel::INFO)<<"CLIENT SAT#"<<buffer;
        }
        else if(ret==0)
        {
            LOG(LogLevel::INFO)<<"CLIENT QUIT...";
            int m=epoll_ctl(_epfd,EPOLL_CTL_DEL,sockfd,nullptr);
            if(m>0)
            {
                LOG(LogLevel::INFO)<<"EPOLL_CTL REMOVE SOCKFD SUCCESS:"<<sockfd;
            }
            close(sockfd);
        }
        else
        {
            LOG(LogLevel::ERROR)<<"RECV ERROR";
            int ret=epoll_ctl(_epfd,EPOLL_CTL_DEL,sockfd,nullptr);
            if (ret>0)
            {
                LOG(LogLevel::INFO)<<"EPOLL_CTL REMOVE SOCKFD SUCCESS:"<<sockfd;
            }
            close(sockfd);
        }
    }
    void Stop()
    {
        _isrunning = false;
    }
    ~EpollServer()
    {
        _listensock->Close();
        if (_epfd>0)
        {
            close(_epfd);
        }
        
    }

private:
    std::unique_ptr<TcpSocket> _listensock;
    bool _isrunning;
    int _epfd;
    struct epoll_event _revs[size];
    
};